#pragma once
#include<iostream>
#include<string>
#include"Log.hpp"
#include"Init.hpp"
using namespace std;

//任务在不同的项目中是不同的，所以要定制化一下tcp通信的任务

//注意：tcp是面向连接的，和udp无连接的不一样：
//一旦TCP连接建立，可以直接使用 write 和 read 系统调用来在客户端和服务器之间进行数据交换，而不需要使用 sendto 和 recvfrom 这样的接口函数。这是因为TCP是一个面向连接的协议，它在数据传输之前已经建立了一个稳定的连接，并且处理了所有的路由和寻址问题。

extern Log lg;
Init init;

class Task 
{
public:
    Task()//提供一个无参默认构造函数，方便我们构造临时的Task对象使用
    {}
   
    Task(int sockfd,const string &clientip,const uint16_t &clientport)
        :sockfd_(sockfd),clientip_(clientip),clientport_(clientport)
    {}
    //执行任务：
    void run()
    {
        char buffer[4096];
        //从连接该客户端对应的文件描述符中读取数据到buffer中
        ssize_t n=read(sockfd_,buffer,sizeof(buffer));
        if(n>0)
        {
            buffer[n]=0;//当字符串使用结尾封\0
            cout<<"client## "<<buffer<<endl;
            string echo_string =init.translation(buffer);//调用init类中的翻译函数（init类维护一个map字典）

            //把翻译结果发送给客户端，只需要在文件描述符中写数据即可（tcp已经建立好连接了）
            n=write(sockfd_,echo_string.c_str(),echo_string.size());
            if(n<0)
            {
                lg(Warning,"write error,errno:%d,errstring:%s",errno,strerror(errno));
            }
        }
        //在TCP连接中，当写方（发送方）关闭套接字后，读方（接收方）将会在下一次尝试从该连接读取数据时收到一个特殊的值：0。这个值表示对端已经关闭了连接，并且没有更多的数据可以读取
        else if(n==0)
        {
            lg(Info,"%s:%d quit,server will close sockfd:%d",clientip_.c_str(),clientport_,sockfd_);
        }
        else
        {
            lg(Warning,"read error,sockfd:%d",sockfd_);
        }
        //我们设计的服务器只会处理客户端一次请求后就结束对该客户端的服务
        close(sockfd_);//无论处理结果怎么样，服务器会关闭目标客户端的连接的文件描述符
        //虽然执行任务的是有一个线程，但是线程是与主线程（服务器）共享的文件描述符资源，所以子线程关闭就等于服务器关闭了该文件描述符
    }
        //补充一个文件描述符管理的文件资源的问题：多个进程打开同一个文件，每个进程都是有自己的文件描述符，此时文件的引用计数是大于1的，只有该文件的引用计数到0，该文件资源就会被操作系统回收，也就是必须所有的打开这个文件资源的进程都关闭了对应的文件描述符，才会让引用计数到0
    void operator()()//重载()运算符
    {
        run();
    }
   
    ~Task()
    {

    }
private:
    //构造任务的时候把目标客户端的信息保存到任务中
    int sockfd_;
    string clientip_;
    uint16_t clientport_;
};